﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using BruteForce.Characters;
using BruteForce.GameObjects;
using BruteForce.Utilities;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Input;

namespace BruteForce.NewManagers {
    public enum CursorState {
        Walk,
        Shoot,
        Idle,
        Generate
    }

    internal class InputManager : Manager {
        public static InputManager Instance = new InputManager();


        private static Keys[] _lastPressedKeys = new Keys[0];

        /// <summary>
        /// return list of all the keyboard keys that was clicked (= was down and now released) in this update
        /// </summary>
        public static List<Keys> CurrentClickedKeys = new List<Keys>();

        public static bool IsShiftDown;
        public int CurMouseX, CurMouseY;
        public MonitoredProperty<bool> MouseClicked = new MonitoredProperty<bool>(false);
        //public MonitoredProperty<bool> MouseHold = new MonitoredProperty<bool>(false);
        private bool _mouseWasPressed;
        private CursorState _state = CursorState.Idle;
        private CharacterType _type;
        protected int UpdateLoopIndex;

        public override void Draw(GameTime gameTime, BFGame game) {
            if (!BFGame.Instance.IsMouseVisible) {
                switch (_state) {
                    case CursorState.Walk:
                        BFGame.SpriteBatch.Draw(BFGame.FootPrintsCursor,
                                                new Rectangle(CurMouseX - 10, CurMouseY - 10,
                                                              BFGame.FootPrintsCursor.Width,
                                                              BFGame.FootPrintsCursor.Height),
                                                Color.White);
                        break;
                    case CursorState.Shoot:
                        BFGame.SpriteBatch.Draw(BFGame.ScopeCursor,
                                                new Rectangle(CurMouseX - 10, CurMouseY - 10, BFGame.ScopeCursor.Width,
                                                              BFGame.ScopeCursor.Height), Color.White);
                        break;
                    case CursorState.Idle:
                        BFGame.SpriteBatch.Draw(BFGame.PointerCursor,
                                                new Rectangle(CurMouseX, CurMouseY, BFGame.PointerCursor.Width,
                                                              BFGame.PointerCursor.Height), Color.White);
                        break;
                    case CursorState.Generate:
                        switch (_type) {
                            case CharacterType.Defender:
                                var defender = PlayerManager.Instance.CurrentPlayer.Property.PlayerType == PlayerType.Human ? Character.VisualMap[new Key("Humans", "Defender", "walking", "sw")][0] : Character.VisualMap[new Key("Monsters", "Defender", "walking", "sw")][0]; 
                                    
                                BFGame.SpriteBatch.Draw(defender, new Rectangle(CurMouseX - defender.Width / 2 + 10, CurMouseY - defender.Height / 2 + 10, BFGame.PointerCursor.Width * 2,
                                                              BFGame.PointerCursor.Height * 2), Color.White);
                                break;
                            case CharacterType.Archer:
                                var archer = PlayerManager.Instance.CurrentPlayer.Property.PlayerType == PlayerType.Human ? Character.VisualMap[new Key("Humans", "Archer", "walking", "sw")][0] : Character.VisualMap[new Key("Monsters", "Archer", "walking", "sw")][0]; 
                                BFGame.SpriteBatch.Draw(archer, new Rectangle(CurMouseX - archer.Width / 2 + 10, CurMouseY - archer.Height / 2 + 10, BFGame.PointerCursor.Width * 2,
                                                              BFGame.PointerCursor.Height * 2), Color.White);
                                break;
                            case CharacterType.Bomber:
                                var bomber = PlayerManager.Instance.CurrentPlayer.Property.PlayerType == PlayerType.Human ? Character.VisualMap[new Key("Humans", "Bomber", "walking", "sw")][0] : Character.VisualMap[new Key("Monsters", "Bomber", "walking", "sw")][0]; 
                                BFGame.SpriteBatch.Draw(bomber, new Rectangle(CurMouseX - bomber.Width / 2 + 10, CurMouseY - bomber.Height / 2 + 10, BFGame.PointerCursor.Width * 2,
                                                              BFGame.PointerCursor.Height * 2), Color.White);
                                break;
                        }
                        break;
                }
            }
        }


        private static void ChangeMouseVisibility(bool visible) {
            BFGame.Instance.IsMouseVisible = visible;
        }

        protected override void _Update(GameTime gameTime, BFGame game) {

            UpdateMouse();
            UpdateKeyBoard();

            if (PlayerManager.Instance.CurrentPlayer.IsChangedSince((UpdateLoopIndex))) {
                Generated();
            }

            UpdateLoopIndex = BFGame.LoopIndex;

        }

        private void UpdateMouse() {
            MouseState ms = Mouse.GetState();

            ms = Mouse.GetState();

            if (!BFGame.Graphics.GraphicsDevice.Viewport.Bounds.Contains(ms.X, ms.Y))
                return;


            CurMouseX = ms.X;
            CurMouseY = ms.Y;

            if (ms.LeftButton == ButtonState.Pressed) {
                if (!_mouseWasPressed) {
                    //MouseHold.Property = true;
                    _mouseWasPressed = true;
                }
            } else if (ms.LeftButton == ButtonState.Released) {
                if (_mouseWasPressed) {
                    _mouseWasPressed = false;
                    //MouseHold.Property = false;
                    MouseClicked.Property = true;
                }
            }
        }


        public override void LoadContent(ContentManager content) {
        }

        public override void Initialize() {
            BFGame.Instance.IsMouseVisible = true;
        }


        public bool IsMouseClickedOn(Rectangle zone) {
            return MouseClicked.Property && zone.Contains(CurMouseX, CurMouseY);
        }

        //public bool IsMousePushed(Rectangle zone)
        //{
        //    return MouseHold.Property && zone.Contains(CurMouseX, CurMouseY);
        //}


        private static void UpdateKeyBoard() {
            CurrentClickedKeys.Clear();
            KeyboardState kbState = Keyboard.GetState();
            Keys[] pressedKeys = kbState.GetPressedKeys();

            //check if any of the previous update's keys are no longer pressed
            foreach (Keys key in _lastPressedKeys) {
                if (!pressedKeys.Contains(key)) {
                    OnKeyUp(key);
                    CurrentClickedKeys.Add(key);
                }
            }

            //save the currently pressed keys so we can compare on the next update
            _lastPressedKeys = pressedKeys;
            IsShiftDown = kbState.IsKeyDown(Keys.LeftShift) || kbState.IsKeyDown(Keys.RightShift);
        }


        private static void OnKeyUp(Keys key) {
            //do stuff
        }

        public Boolean KeyWasPressed(Keys key) {
            return CurrentClickedKeys.Contains(key);
        }

        public void ChangeCursor(CharacterState characterState) {
            switch (characterState) {
                case CharacterState.PrepareToWalk:
                    ChangeMouseVisibility(false);
                    _state = CursorState.Walk;
                    break;
                case CharacterState.PrepareToShoot:
                    ChangeMouseVisibility(false);
                    _state = CursorState.Shoot;
                    break;
                case CharacterState.Idle:
                    case CharacterState.Walking:
                    case CharacterState.Shooting:
                    ChangeMouseVisibility(true);
                    _state = CursorState.Idle;
                    break;
            }
        }

        public void ChangeCursorGenerate() {
            ChangeMouseVisibility(false);
            _state = CursorState.Generate;
        }


        public void Generate(CharacterType characterType) {
            ChangeCursorGenerate();
            _type = characterType;
        }

        public void Generated() {
            ChangeMouseVisibility(true);
            _state = CursorState.Idle;
        }
    }
}